// cmd/geni18n/main.go
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/goccy/go-yaml"
)

func main() {
	dir := flag.String("dir", "./common/i18n/locale", "Locales directory path")
	out := flag.String("out", "common/i18n/i18nk/keys.go", "Output file path")
	pkg := flag.String("pkg", "i18nk", "Package name for generated file")
	flag.Parse()

	keys := make(map[string]struct{})

	err := filepath.WalkDir(*dir, func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		if d.IsDir() || !(strings.HasSuffix(d.Name(), ".yaml") || strings.HasSuffix(d.Name(), ".yml")) {
			return nil
		}

		data, err := os.ReadFile(path)
		if err != nil {
			return err
		}

		var content map[string]interface{}
		if err := yaml.Unmarshal(data, &content); err != nil {
			return fmt.Errorf("failed to parse yaml %s: %w", path, err)
		}

		collectKeys(content, "", keys)
		return nil
	})
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error walking directory: %v\n", err)
		os.Exit(1)
	}

	var list []string
	for k := range keys {
		list = append(list, k)
	}
	sort.Strings(list)

	f, err := os.Create(*out)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error creating output file: %v\n", err)
		os.Exit(1)
	}
	defer f.Close()

	w := bufio.NewWriter(f)
	fmt.Fprintf(w, "// Code generated by cmd/geni18n. DO NOT EDIT.\n")
	fmt.Fprintf(w, "package %s\n\n", *pkg)
	fmt.Fprintf(w, "type Key string\n\n")
	fmt.Fprintf(w, "const (\n")
	for _, key := range list {
		name := toPascal(key)
		fmt.Fprintf(w, "\t%s Key = %q\n", name, key)
	}
	fmt.Fprintf(w, ")\n")
	w.Flush()
}

func collectKeys(node map[string]interface{}, prefix string, keys map[string]struct{}) {
	for k, v := range node {
		fullKey := k
		if prefix != "" {
			fullKey = prefix + "." + k
		}
		switch val := v.(type) {
		case map[string]interface{}:
			collectKeys(val, fullKey, keys)
		default:
			keys[fullKey] = struct{}{}
		}
	}
}

// 转 PascalCase
func toPascal(key string) string {
	parts := strings.Split(key, ".")
	for i, p := range parts {
		subs := strings.Split(p, "_")
		for j, s := range subs {
			if len(s) > 0 {
				subs[j] = strings.ToUpper(s[:1]) + s[1:]
			}
		}
		parts[i] = strings.Join(subs, "")
	}
	return strings.Join(parts, "")
}
